package com.dtp.common.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;

import java.util.Map;

/**
 * 提供Bean相关操作的工具类
 *
 * @author yanhom
 * @since 1.0.4
 *
 * @remark muse
 **/
@Slf4j
public final class BeanUtil {

    private BeanUtil() { }

    /** 向Spring中注册beanDefinition，如果已经注册过，则删除掉重新注册 */
    public static void registerIfAbsent(BeanDefinitionRegistry registry, String beanName, Class<?> clazz,
                                        Map<String, Object> propertyValues, Object... constructorArgs) {
        // 如果beanDefinition已经存在了，则移除旧的beanDefinition
        if (ifPresent(registry, beanName, clazz) || registry.containsBeanDefinition(beanName))
            registry.removeBeanDefinition(beanName);

        // 注册Bean的配置信息
        doRegister(registry, beanName, clazz, propertyValues, constructorArgs);
    }

    /** 判断名称为beanName的Bean是否已经注册到Spring中 */
    public static boolean ifPresent(BeanDefinitionRegistry registry, String beanName, Class<?> clazz) {
        String[] beanNames = getBeanNames((ListableBeanFactory) registry, clazz);
        return ArrayUtils.contains(beanNames, beanName);
    }

    /** 获得Spring中所有clazz类型的beanName列表 */
    public static String[] getBeanNames(ListableBeanFactory beanFactory, Class<?> clazz) {
        return beanFactory.getBeanNamesForType(clazz, true, false);
    }

    /** 执行beanDefinition的注册操作 */
    public static void doRegister(BeanDefinitionRegistry registry, String beanName, Class<?> clazz,
                                  Map<String, Object> propertyValues, Object... constructorArgs) {
        // 获得clazz类型的BeanDefinitionBuilder
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);

        // 向builder中添加构造函数的参数
        for (Object constructorArg : constructorArgs) builder.addConstructorArgValue(constructorArg);

        // 向builder中添加属性值，key为属性，Object为值
        if (MapUtils.isNotEmpty(propertyValues)) propertyValues.forEach(builder::addPropertyValue);

        // 创建BeanDefinition并注册到Spring中
        registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
    }
}
